/*--------------------------+
|	   Particle Class		|
|	---------------------	|
|	Manages the data for,	|
|	updates, and renders	|
|	indivudual particles	|
+--------------------------*/

#include "Particle.h"
#include "SGD Wrappers\CSGD_Direct3D.h"
#include "SGD Wrappers\CSGD_TextureManager.h"

// Constructor
Particle::Particle(int image, float lifespan, DWORD color, DWORD endcolor, float startscale, float endscale, tVector2D position, tVector2D direction, float velocity, float rotation, float rotationspeed, D3DBLEND src, D3DBLEND dest)
{
	// The image
	ImageID = image;

	if( ImageID != -1 )
	{
		Width = CSGD_TextureManager::GetInstance()->GetTextureWidth(ImageID);
		Height = CSGD_TextureManager::GetInstance()->GetTextureHeight(ImageID);
	}

	// Other basic data
	Lifetime = lifespan;
	TimeOfDeath = GetTickCount() + lifespan * 1000;
	StartColor = color;
	CurrentColor = color;
	EndColor = endcolor;
	StartScale = startscale;
	CurrentScale = startscale;
	EndScale = endscale;
	Position = position;
	Direction = direction;
	Velocity = velocity;
	Rotation = rotation;
	RotationSpeed = rotationspeed;
	Destroy = false;

	// The blend mode
	SourceBlend = src;
	DestBlend = dest;
	
	// Individual rgb values
	a1 = color >> 24;
	r1 = (color >> 16) & 0xFF;
	g1 = (color >> 8 ) & 0xFF;
	b1 = color & 0xFF;
	a2 = color >> 24;
	r2 = (endcolor >> 16) & 0xFF;
	g2 = (endcolor >> 8 ) & 0xFF;
	b2 = endcolor & 0xFF;
}

// Copy Constructor
Particle::Particle(const Particle& other)
{
	// Basic data
	ImageID = other.ImageID;
	Width = other.Width;
	Height = other.Height;
	Lifetime = other.Lifetime;
	TimeOfDeath = GetTickCount() + Lifetime * 1000;
	StartColor = other.StartColor;
	CurrentColor = StartColor;
	EndColor = other.EndColor;
	StartScale = other.StartScale;
	CurrentScale = StartScale;
	EndScale = other.EndScale;
	Position = other.Position;
	Direction = other.Direction;
	Velocity = other.Velocity;
	Rotation = other.Rotation;
	RotationSpeed = other.RotationSpeed;
	Destroy = false;

	// Blend modes
	DestBlend = other.DestBlend;
	SourceBlend = other.SourceBlend;

	// The individual rgb values
	a1 = other.a1;
	r1 = other.r1;
	g1 = other.g1;
	b1 = other.b1;
	a2 = other.a2;
	r2 = other.r2;
	g2 = other.g2;
	b2 = other.b2;
}

// Destructor
Particle::~Particle(void)
{

}

// Render
void Particle::Render(void) const
{
	// If there isn't an associated image, just draw a rect
	if( ImageID == -1 )
	{
		return;
	}

	CSGD_Direct3D::GetInstance()->GetDirect3DDevice()->SetRenderState(D3DRS_SRCBLEND,SourceBlend);
	CSGD_Direct3D::GetInstance()->GetDirect3DDevice()->SetRenderState(D3DRS_DESTBLEND,DestBlend);

	// Draw the texture
	int x = Position.fX - Width/2 * CurrentScale;
	int y = Position.fY - Height/2 * CurrentScale;
	CSGD_TextureManager::GetInstance()->Draw(ImageID,x,y,CurrentScale,CurrentScale,0,Width/2,Height/2,Rotation,CurrentColor);
}

// Update
void Particle::Update(float elapsedTime)
{
	// Convert Lifetime to ms
	DWORD l = Lifetime * 1000;

	// Find percent of lifetime expired
	float percent = (l - (TimeOfDeath - GetTickCount()))/l;

	// Determine the current color
	BYTE a, r, b, g;

	a = Lerp(a1,a2,percent);
	r = Lerp(r1,r2,percent);
	g = Lerp(g1,g2,percent);
	b = Lerp(b1,b2,percent);

	CurrentColor = D3DCOLOR_ARGB(a,r,g,b);

	// Determine the current scale size
	CurrentScale = Lerp(StartScale,EndScale,percent);

	// Calculate the velocity and direction
	tVector2D MoveVec;
	MoveVec.fX = 0;
	MoveVec.fY = Velocity * elapsedTime;
	MoveVec = Vector2DRotate(MoveVec,Rotation);

	// Move the Particle
	Position.fX += MoveVec.fX; 
	Position.fY += MoveVec.fY;

	Position = Position + Direction * elapsedTime;

	// Update the rotation
	Rotation += RotationSpeed * elapsedTime;

	// Determine if the particle should be destroyed
	if( GetTickCount() > TimeOfDeath )
		Destroy = true;
}

// Change the life and death times
void Particle::SetLifetime(float lifetime)
{
	Lifetime = lifetime;
	TimeOfDeath = GetTickCount() + lifetime * 1000;
}

// Randomize values
void Particle::RandomizeScale(float range)
{
	if( !range )
		return;
	float change = (float)rand()/(float)RAND_MAX * range;
	if( rand() % 2 )
	{
		StartScale += change;
		EndScale += change;
	}
	else
	{
		StartScale -= change;
		EndScale -= change;
	}
}

void Particle::RandomizePosition(float xrange, float yrange)
{
	if( !xrange && !yrange )
		return;
	float change = (float)rand()/(float)RAND_MAX * xrange;
	if( rand() % 2 )
		Position.fX += change;
	else
		Position.fX -= change;
	change = (float)rand()/(float)RAND_MAX * yrange;
	if( rand() % 2 )
		Position.fY += change;
	else
		Position.fY -= change;
}

void Particle::RandomizeVelocity(float range)
{
	if( !range )
		return;
	float change = (float)rand()/(float)RAND_MAX * range;
	if( rand() % 2 )
		Velocity += change;
	else
		Velocity -= change;
}

void Particle::RandomizeRotation(float range)
{
	if( !range )
		return;
	float change = (float)rand()/(float)RAND_MAX * range;
	if( rand() % 2 )
		Rotation += change;
	else
		Rotation -= change;
}

void Particle::RandomizeRotationSpeed(float range)
{
	if( !range )
		return;
	float change = (float)rand()/(float)RAND_MAX * range;
	if( rand() % 2 )
		RotationSpeed += change;
	else
		RotationSpeed -= change;
}

void Particle::RandomizeLifetime(float range)
{
	if( !range )
		return;
	float change = (float)rand()/(float)RAND_MAX * range;
	if( rand() % 2 )
		SetLifetime( Lifetime + change );
	else
		SetLifetime( Lifetime - change );
}

void Particle::SetBlendMode(D3DBLEND src, D3DBLEND dest)
{
	SourceBlend = src;
	DestBlend = dest;
}